home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ABUSESRC.ZIP / AbuseSrc / abuse / src / light.c < prev    next >
C/C++ Source or Header  |  1996-04-15  |  31KB  |  1,279 lines

  1. #include "light.hpp"
  2. #include <stdlib.h>
  3. #include "image.hpp"
  4. #include "macs.hpp"
  5. #include "video.hpp"
  6. #include "palette.hpp"
  7. #include "timing.hpp"
  8. #include "specs.hpp"
  9. #include "dprint.hpp"
  10. #include "filter.hpp"
  11. #include "status.hpp"
  12. #include "dev.hpp"
  13.  
  14. light_source *first_light_source=NULL;
  15. unsigned char *white_light,*white_light_initial,*green_light,*trans_table;
  16. short ambient_ramp=0;
  17. short shutdown_lighting_value,shutdown_lighting=0;
  18. extern char disable_autolight;   // defined in dev.hpp
  19.  
  20. int light_detail=MEDIUM_DETAIL;
  21.  
  22. long light_to_number(light_source *l)
  23. {
  24.   
  25.   if (!l) return 0;
  26.   int x=1;
  27.   for (light_source *s=first_light_source;s;s=s->next,x++)
  28.     if (s==l) return x;
  29.   return 0;
  30. }
  31.  
  32.  
  33. light_source *number_to_light(long x)
  34. {
  35.   if (x==0) return NULL;
  36.   x--;
  37.   light_source *s=first_light_source;
  38.   for (;x && s;x--,s=s->next);
  39.   return s;       
  40. }
  41.  
  42. light_source *light_source::copy()
  43. {
  44.   next=new light_source(type,x,y,inner_radius,outer_radius,xshift,yshift,next);
  45.   return next;
  46. }
  47.  
  48. void delete_all_lights()
  49. {
  50.   while (first_light_source)
  51.   {
  52.     if (dev_cont)
  53.       dev_cont->notify_deleted_light(first_light_source);
  54.  
  55.     light_source *p=first_light_source;
  56.     first_light_source=first_light_source->next;
  57.     delete p;
  58.   }
  59. }
  60.  
  61. void delete_light(light_source *which)
  62. {
  63.   if (dev_cont)
  64.     dev_cont->notify_deleted_light(which);
  65.  
  66.   if (which==first_light_source)
  67.   {
  68.     first_light_source=first_light_source->next;
  69.     delete which;
  70.   }
  71.   else
  72.   {
  73.     light_source *f=first_light_source;
  74.     for (;f->next!=which && f;f=f->next);
  75.     if (f)
  76.     {
  77.       f->next=which->next;
  78.       delete which;
  79.     }
  80.   }
  81. }
  82.  
  83. void light_source::calc_range()
  84. {
  85.   switch (type)
  86.   {
  87.     case 0 :
  88.     { x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
  89.       x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
  90.     } break;
  91.     case 1 :
  92.     { x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
  93.       x2=x+(outer_radius>>xshift); y2=y;
  94.     } break;
  95.     case 2 :
  96.     { x1=x-(outer_radius>>xshift); y1=y;
  97.       x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
  98.     } break;
  99.     case 3 :
  100.     { x1=x; y1=y-(outer_radius>>yshift);
  101.       x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
  102.     } break;
  103.     case 4 :
  104.     { x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
  105.       x2=x; y2=y+(outer_radius>>yshift);
  106.     } break;
  107.  
  108.  
  109.     case 5 :
  110.     { x1=x; y1=y-(outer_radius>>yshift);
  111.       x2=x+(outer_radius>>xshift); y2=y;
  112.     } break;
  113.     case 6 :
  114.     { x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
  115.       x2=x; y2=y;
  116.     } break;
  117.     case 7 :
  118.     { x1=x-(outer_radius>>xshift); y1=y;
  119.       x2=x; y2=y+(outer_radius>>yshift);
  120.     } break;
  121.     case 8 :
  122.     { x1=x; y1=y;
  123.       x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
  124.     } break;
  125.     case 9 :
  126.     {
  127.       x1=x;
  128.       y1=y;
  129.       x2=x+xshift;
  130.       y2=y+yshift;
  131.     } break;
  132.  
  133.   }
  134.   mul_div=(1<<16)/(outer_radius-inner_radius)*64;
  135. }
  136.  
  137. light_source::light_source(char Type, long X, long Y, long Inner_radius, 
  138.                long Outer_radius, long Xshift,  long Yshift, light_source *Next)
  139.   type=Type; 
  140.   x=X; y=Y; 
  141.   inner_radius=Inner_radius;  
  142.   outer_radius=Outer_radius; 
  143.   next=Next; 
  144.   known=0;
  145.   xshift=Xshift;
  146.   yshift=Yshift;
  147.   calc_range(); 
  148. }
  149.  
  150.  
  151. int count_lights()
  152. {
  153.   int t=0;
  154.   for (light_source *s=first_light_source;s;s=s->next)
  155.     t++;
  156.   return t;
  157. }
  158.  
  159. light_source *add_light_source(char type, long x, long y, 
  160.                    long inner, long outer, long xshift, long yshift)
  161. {
  162.   first_light_source=new light_source(type,x,y,inner,outer,xshift,yshift,first_light_source);
  163.   return first_light_source;
  164. }
  165.  
  166.  
  167. #define TTINTS 9
  168. uchar *tints[TTINTS];
  169. uchar bright_tint[256];
  170.  
  171. void calc_tint(uchar *tint, int rs, int gs, int bs, int ra, int ga, int ba, palette *pal)
  172. {
  173.   palette npal;
  174.   memset(npal.addr(),0,256);
  175.   int i=0;
  176.   for (;i<256;i++)
  177.   {
  178.     npal.set(i,(int)rs,(int)gs,(int)bs);
  179.     rs+=ra; if (rs>255) rs=255; if (rs<0) rs=0;
  180.     gs+=ga; if (gs>255) gs=255; if (gs<0) gs=0;
  181.     bs+=ba; if (bs>255) bs=255; if (bs<0) bs=0;
  182.   }
  183.   filter f(pal,&npal);
  184.   filter f2(&npal,pal);
  185.  
  186.   for (i=0;i<256;i++,tint++)
  187.     *tint=f2.get_mapping(f.get_mapping(i));
  188. }
  189.  
  190.  
  191. void calc_light_table(palette *pal)
  192. {
  193.   
  194.   white_light_initial=(unsigned char *)jmalloc(256*64,"light table");
  195.   white_light=white_light_initial;
  196.  
  197. //  green_light=(unsigned char *)jmalloc(256*64,"green light");
  198.   int i=0;
  199.   for (;i<TTINTS;i++)
  200.       tints[i]=(uchar *)jmalloc(256,"color tint");
  201.  
  202.   bFILE *fp=open_file("light.tbl","rb");
  203.   int recalc=0;
  204.   if (fp->open_failure()) 
  205.   {
  206.     recalc=1;
  207.     delete fp;
  208.   }
  209.   else
  210.   {
  211.     if (fp->read_short()!=calc_crc((unsigned char *)pal->addr(),768))
  212.       recalc=1;
  213.     else
  214.     {
  215.       fp->read(white_light,256*64);
  216. //      fp->read(green_light,256*64);
  217.       for (i=0;i<TTINTS;i++)
  218.         fp->read(tints[i],256);
  219.       fp->read(bright_tint,256);
  220. //      trans_table=(uchar *)jmalloc(256*256,"transparency table");
  221. //      fp.read(trans_table,256*256);
  222.     }
  223.     delete fp;
  224.   }
  225.  
  226.   if (recalc)
  227.   {  
  228.     fprintf(stderr,"Palette has changed, recalculating light table...\n");
  229.     stat_man->push("white light",NULL);
  230.     int color=0;
  231.     for (;color<256;color++)
  232.     {
  233.       unsigned char r,g,b;
  234.       pal->get(color,r,g,b);
  235.       stat_man->update(color*100/256);
  236.       for (int intensity=63;intensity>=0;intensity--)
  237.       {
  238.     if (r>0 || g>0 || b>0)
  239.           white_light[intensity*256+color]=pal->find_closest(r,g,b);
  240.     else
  241.           white_light[intensity*256+color]=0;
  242.     if (r) r--;  if (g) g--;  if (b) b--;     
  243.       } 
  244.  
  245.  
  246.  
  247.     }
  248.     stat_man->pop();
  249.  
  250. /*    stat_man->push("green light",NULL);
  251.     for (color=0;color<256;color++)
  252.     {
  253.       stat_man->update(color*100/256);
  254.       unsigned char r,g,b;
  255.       pal->get(color,b,r,g);
  256.       r=r*3/5; b=b*3/5; g+=7; if (g>255) g=255;
  257.  
  258.       for (int intensity=63;intensity>=0;intensity--)
  259.       {
  260.     if (r>0 || g>0 || b>0)
  261.           green_light[intensity*256+color]=pal->find_closest(r,g,b);
  262.     else
  263.           green_light[intensity*256+color]=0;
  264.     if (r) r--;  
  265.     if ((intensity&1)==1)
  266.       if (g) g--;  
  267.     if (b) b--;
  268.       }
  269.     }
  270.     stat_man->pop(); */
  271.  
  272.     stat_man->push("tints",NULL);
  273.     uchar t[TTINTS*6]={0,0,0,0,0,0, // normal
  274.                    0,0,0,1,0,0,     // red
  275.            0,0,0,1,1,0,     // yellow
  276.            0,0,0,1,0,1,     // purple
  277.            0,0,0,1,1,1,     // gray
  278.            0,0,0,0,1,0,     // green
  279.            0,0,0,0,0,1,     // blue
  280.            0,0,0,0,1,1,     // cyan 
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.            0,0,0,0,0,0   // reverse green  (night vision effect)
  288.          } ;
  289.     uchar *ti=t+6;
  290.     uchar *c;
  291.     for (i=0,c=tints[0];i<256;i++,c++) *c=i;  // make the normal tint (maps everthing to itself)
  292.     for (i=0,c=tints[TTINTS-1];i<256;i++,c++)  // reverse green
  293.     {
  294.       int r=pal->red(i)/2,g=255-pal->green(i)-30,b=pal->blue(i)*3/5+50;
  295.       if (g<0) g=0;
  296.       if (b>255) b=0;
  297.       *c=pal->find_closest(r,g,b);
  298.     }
  299.     for (i=0;i<256;i++)
  300.     {
  301.       int r=pal->red(i)+(255-pal->red(i))/2,
  302.           g=pal->green(i)+(255-pal->green(i))/2,
  303.           b=pal->blue(i)+(255-pal->blue(i))/2;
  304.       bright_tint[i]=pal->find_closest(r,g,b);
  305.     }
  306.  
  307.     // make the colored tints
  308.     for (i=1;i<TTINTS-1;i++)
  309.     {
  310.       stat_man->update(i*100/(TTINTS-1));
  311.       calc_tint(tints[i],ti[0],ti[1],ti[2],ti[3],ti[4],ti[5],pal);
  312.       ti+=6;
  313.     }
  314.     stat_man->pop();
  315. /*    fprintf(stderr,"calculating transparency tables (256 total)\n");
  316.     trans_table=(uchar *)jmalloc(256*256,"transparency table");
  317.  
  318.     uchar *tp=trans_table;
  319.     for (i=0;i<256;i++)
  320.     {      
  321.       uchar r1,g1,b1,r2,g2,b2;
  322.       pal->get(i,r1,g1,b1);
  323.       if ((i%16)==0)
  324.         fprintf(stderr,"%d ",i);
  325.       for (int j=0;j<256;j++,tp++)
  326.       {
  327.     if (r1==0 && r2==0 && b2==0)
  328.       *tp=j;
  329.     else
  330.     {
  331.       pal->get(j,r2,g2,b2);       
  332.       *tp=pal->find_closest((r2-r1)*3/7+r1,(g2-g1)*3/7+g1,(b2-b1)*3/7+b1);
  333.     }
  334.       }
  335.     }*/
  336.  
  337.  
  338.     bFILE *f=open_file("light.tbl","wb");
  339.     if (f->open_failure())    
  340.       dprintf("Unable to open file light.tbl for writing\n");
  341.     else
  342.     {
  343.       f->write_short(calc_crc((unsigned char *)pal->addr(),768));
  344.       f->write(white_light,256*64);
  345. //      f->write(green_light,256*64);
  346.       for (int i=0;i<TTINTS;i++)
  347.         f->write(tints[i],256);
  348.       fp->write(bright_tint,256);
  349. //    f.write(trans_table,256*256);
  350.     }
  351.     delete f;
  352.   }
  353. }
  354.  
  355.  
  356. light_patch *light_patch::copy(light_patch *Next)
  357.   light_patch *p=new light_patch(x1,y1,x2,y2,Next); 
  358.   p->total=total;
  359.   if (total)    
  360.   {
  361.     p->lights=(light_source **)jmalloc(total*sizeof(light_source *),"light patches");
  362.     memcpy(p->lights,lights,total*(sizeof(light_source *)));
  363.   }
  364.   else 
  365.     p->lights=NULL; 
  366.   return p;
  367. }
  368.  
  369. #define MAX_LP 6
  370.  
  371. // insert light into list make sure the are sorted by y1
  372. void insert_light(light_patch *&first, light_patch *l)
  373. {
  374.   if (!first)
  375.     first=l;
  376.   else if (l->y1<first->y1)
  377.   {
  378.     l->next=first;
  379.     first=l;
  380.   } else
  381.   {
  382.     light_patch *p=first;
  383.     for (;p->next && p->next->y1<l->y1;p=p->next);
  384.     l->next=p->next;
  385.     p->next=l;
  386.   }
  387. }
  388.  
  389. void add_light(light_patch *&first, long x1, long y1, long x2, long y2, 
  390.                 light_source *who)
  391. {  
  392.   light_patch *last=NULL,*next;
  393.   light_patch *p=first;
  394.   for (;p;p=next)
  395.   {
  396.     next=p->next;
  397.     // first see if light patch we are adding is enclosed entirely by another patch
  398.     if (x1>=p->x1 && y1>=p->y1 && x2<=p->x2 && y2<=p->y2)
  399.     {
  400.       if (p->total==MAX_LP) return ;
  401.  
  402.       if (x1>p->x1)
  403.       {
  404.     light_patch *l=p->copy(NULL);
  405.     l->x2=x1-1;
  406.     insert_light(first,l);
  407.       }
  408.       if (x2<p->x2)
  409.       {
  410.     light_patch *l=p->copy(NULL);
  411.     l->x1=x2+1;
  412.     insert_light(first,l);
  413.       }
  414.       if (y1>p->y1)
  415.       {
  416.     light_patch *l=p->copy(NULL);
  417.     l->x1=x1;
  418.     l->x2=x2;
  419.     l->y2=y1-1;
  420.     insert_light(first,l);
  421.       }
  422.       if (y2<p->y2)
  423.       {
  424.     light_patch *l=p->copy(NULL);
  425.     l->x1=x1;
  426.     l->x2=x2;
  427.     l->y1=y2+1;
  428.     insert_light(first,l);
  429.       }
  430.       p->x1=x1; p->y1=y1; p->x2=x2; p->y2=y2;
  431.       // p has possibly changed it's y1, so we need to move it to it's correct sorted 
  432.       // spot in the list
  433.       if (first==p)
  434.         first=first->next;
  435.       else
  436.       {
  437.     light_patch *q=first;
  438.     for (;q->next!=p;q=q->next);
  439.     q->next=p->next;
  440.       }
  441.       insert_light(first,p);
  442.       
  443.  
  444.       p->total++;     
  445.       p->lights=(light_source **)jrealloc(p->lights,sizeof(light_source *)*p->total,"patch_list");
  446.       p->lights[p->total-1]=who;
  447.       return ;
  448.     }
  449.  
  450.     // see if the patch completly covers another patch.
  451.     if (x1<=p->x1 && y1<=p->y1 && x2>=p->x2 && y2>=p->y2)
  452.     {
  453.       if (x1<p->x1)
  454.         add_light(first,x1,y1,p->x1-1,y2,who);
  455.       if (x2>p->x2)
  456.         add_light(first,p->x2+1,y1,x2,y2,who);
  457.       if (y1<p->y1)
  458.         add_light(first,p->x1,y1,p->x2,p->y1-1,who);
  459.       if (y2>p->y2)
  460.         add_light(first,p->x1,p->y2+1,p->x2,y2,who);
  461.       if (p->total==MAX_LP)  return ;
  462.       p->total++;     
  463.       p->lights=(light_source **)jrealloc(p->lights,sizeof(light_source *)*p->total,"patch_list");
  464.       p->lights[p->total-1]=who;
  465.       return ;
  466.     }
  467.  
  468.     // see if we intersect another rect
  469.     if (!(x2<p->x1 || y2<p->y1 || x1>p->x2 || y1>p->y2))  
  470.     {
  471.       int ax1,ay1,ax2,ay2;
  472.       if (x1<p->x1)
  473.       {
  474.         add_light(first,x1,max(y1,p->y1),p->x1-1,min(y2,p->y2),who);
  475.     ax1=p->x1;
  476.       } else
  477.     ax1=x1;
  478.  
  479.       if (x2>p->x2)
  480.       {
  481.         add_light(first,p->x2+1,max(y1,p->y1),x2,min(y2,p->y2),who);
  482.     ax2=p->x2;
  483.       } 
  484.       else
  485.     ax2=x2;
  486.  
  487.       if (y1<p->y1)
  488.       {       
  489.         add_light(first,x1,y1,x2,p->y1-1,who);
  490.     ay1=p->y1;
  491.       } else 
  492.     ay1=y1;
  493.  
  494.       if (y2>p->y2)
  495.       {
  496.         add_light(first,x1,p->y2+1,x2,y2,who);
  497.     ay2=p->y2;
  498.       } else 
  499.     ay2=y2;
  500.  
  501.        
  502.       add_light(first,ax1,ay1,ax2,ay2,who);      
  503.  
  504.       return ;    
  505.     }
  506.   }
  507. }
  508.  
  509. light_patch *find_patch(int screenx, int screeny, light_patch *list)
  510. {
  511.   for (;list;list=list->next)
  512.   {
  513.     if (screenx>=list->x1 && screenx<=list->x2 && screeny>=list->y1 && screeny<=list->y2)
  514.       return list;
  515.   }
  516.   return NULL;
  517. }
  518.  
  519. /* shit
  520. int calc_light_value(light_patch *which, long x, long y)
  521. {
  522.   int lv=0;
  523.   int t=which->total;
  524.   for (register int i=t-1;i>=0;i--)
  525.   {    
  526.     light_source *fn=which->lights[i];
  527.     if (fn->type==9)
  528.     {
  529.       lv=fn->inner_radius;
  530.       i=0;
  531.     }
  532.     else
  533.     {
  534.       long dx=abs(fn->x-x)<<fn->xshift;
  535.       long dy=abs(fn->y-y)<<fn->yshift;
  536.       long  r2;
  537.       if (dx<dy)
  538.         r2=dx+dy-(dx>>1);
  539.       else r2=dx+dy-(dy>>1);
  540.     
  541.       if (r2>=fn->inner_radius)
  542.       {
  543.     if (r2<fn->outer_radius)
  544.     {
  545.       lv+=((fn->outer_radius-r2)*fn->mul_div)>>16;
  546.     }
  547.       } else lv=63;      
  548.     }
  549.   }
  550.   if (lv>63) return 63; 
  551.   else
  552.     return lv;
  553. } */
  554.  
  555.  
  556. void reduce_patches(light_patch *f)   // find constant valued patches
  557. {
  558.   
  559. }
  560.  
  561. light_patch *make_patch_list(int width, int height, long screenx, long screeny)
  562. {
  563.   light_patch *first=new light_patch(0,0,width-1,height-1,NULL);
  564.  
  565.   for (light_source *f=first_light_source;f;f=f->next)   // determine which lights will have effect
  566.   {
  567.     long x1=f->x1-screenx,y1=f->y1-screeny,
  568.         x2=f->x2-screenx,y2=f->y2-screeny;
  569.     if (x1<0) x1=0;
  570.     if (y1<0) y1=0;
  571.     if (x2>=width)  x2=width-1;
  572.     if (y2>=height) y2=height-1;
  573.  
  574.     if (x1<=x2 && y1<=y2)
  575.       add_light(first,x1,y1,x2,y2,f);
  576.   }
  577.   reduce_patches(first);
  578.  
  579.   return first;
  580. }
  581.  
  582.  
  583. void delete_patch_list(light_patch *first)
  584. {
  585.   while (first)
  586.   {
  587.     light_patch *p=first;
  588.     first=first->next;
  589.     delete p;
  590.   }
  591. }
  592.  
  593. /*
  594. #ifdef __WATCOMC__
  595. extern "C" {
  596. extern long MAP_PUT(long pad, long screen_addr, long remap, long w);
  597. } ;
  598. #else*/
  599.  
  600. inline void MAP_PUT(long screen_addr, long remap, long w)
  601.   register int cx=w;
  602.   register int di=screen_addr;
  603.   register int si=remap;
  604.   while (cx--) 
  605.     *((uchar *)(di++))=*((uchar *)si+*((uchar *)di)); 
  606. }
  607.  
  608. inline void MAP_2PUT(long in_addr, long out_addr, long remap, long w)
  609.   while (w--) 
  610.   {
  611.     uchar x=*(((uchar *)remap)+(*(uchar *)(in_addr++)));
  612.     *((uchar *)(out_addr++))=x;
  613.     *((uchar *)(out_addr++))=x;
  614.   }
  615. }
  616.  
  617. /*
  618. #endif
  619.  
  620. inline void PUT8(long *addr, uchar *remap)
  621. {
  622.   register ulong in_pixels;
  623.   register ulong pixel;
  624.   register ulong out_pixels;
  625.   in_pixels=*addr;
  626.   pixel=in_pixels;
  627.   out_pixels=remap[(uchar)pixel];
  628.   
  629.   pixel=in_pixels;
  630.   pixel>>=8;
  631.   pixel=remap[(uchar)pixel];
  632.   pixel<<=8;
  633.   out_pixels|=pixel;
  634.  
  635.   pixel=in_pixels;
  636.   pixel>>=16;
  637.   pixel=remap[(uchar)pixel];
  638.   pixel<<=16;
  639.   out_pixels|=pixel;
  640.  
  641.   pixel=in_pixels;
  642.   pixel>>=24;
  643.   pixel=remap[(uchar)pixel];
  644.   pixel<<=24;
  645.   out_pixels|=pixel;
  646.  
  647.   *addr=out_pixels;        // send out bus
  648.  
  649.   // do next 4
  650.   in_pixels=addr[1];
  651.  
  652.   pixel=in_pixels;
  653.   pixel&=0xff;
  654.   out_pixels=remap[pixel];
  655.   
  656.   pixel=in_pixels;
  657.   pixel>>=8;
  658.   pixel=remap[(uchar)pixel];
  659.   pixel<<=8;
  660.   out_pixels|=pixel;
  661.  
  662.   pixel=in_pixels;
  663.   pixel>>=16;
  664.   pixel=remap[(uchar)pixel];
  665.   pixel<<=16;
  666.   out_pixels|=pixel;
  667.  
  668.   pixel=in_pixels;
  669.   pixel>>=24;
  670.   pixel=remap[(uchar)pixel];
  671.   pixel<<=24;
  672.   out_pixels|=pixel;  
  673.   addr[1]=out_pixels;        // send out bus
  674.   
  675. }
  676.  
  677. inline long MAP_PUT2(long dest_addr, long screen_addr, long remap, long w)
  678. { while (w--) 
  679.   { 
  680.     *((uchar *)(dest_addr))=*((uchar *)remap+*((uchar *)screen_addr)); 
  681.     screen_addr++; 
  682.     dest_addr++;
  683.   } 
  684.   return dest_addr;
  685. }
  686.  
  687. */
  688.  
  689. ushort min_light_level;
  690. // calculate the light value for this block.  sum up all contritors
  691. inline int calc_light_value(light_patch *lp,   // light patch to look at
  692.                 long sx,           // screen x & y
  693.                 long sy)
  694. {
  695.   int lv=min_light_level,r2,light_count;
  696.   register int dx,dy;           // x and y distances
  697.  
  698.   light_source **lon_p=lp->lights;
  699.  
  700.   for (light_count=lp->total;light_count>0;light_count--)
  701.   {
  702.     light_source *fn=*lon_p;
  703.     register long *dt=&(*lon_p)->type; 
  704.                                      // note we are accessing structure members by bypassing the compiler
  705.                                      // for speed, this may not work on all compilers, but don't
  706.                                      // see why it shouldn't..  all members are long
  707.     
  708.     if (*dt==9)                      // (dt==type),  if light is a Solid rectangle, return it value
  709.       return fn->inner_radius;
  710.     else
  711.     {
  712.       dt++;
  713.       dx=abs(*dt-sx); dt++;               // xdist between light and this block  (dt==x)
  714.       dx<<=*dt;  dt++;                    // shift makes distance further, 
  715.                                           // making light skinner. (dt==xshift)
  716.  
  717.       dy=abs(*dt-sy); dt++;                   // ydist (dt==y)
  718.       dy<<=*dt;  dt++;                        // (dt==yshift)
  719.  
  720.       if (dx<dy)                     // calculate approximate distance
  721.         r2=dx+dy-(dx>>1);
  722.       else r2=dx+dy-(dy>>1);
  723.       
  724.       if (r2<*dt)                    // if this withing the light's outer radius?  (dt==outer_radius)
  725.       {        
  726.     int v=*dt-r2; dt++;        
  727.     lv+=v*(*dt)>>16;
  728.       }
  729.     }
  730.     lon_p++;
  731.   }
  732.  
  733.   if (lv>63) 
  734.     return 63;          // lighting table only has 64 (256 bytes) entries 
  735.   else return lv;
  736. }
  737.  
  738.  
  739. /*#ifdef __WATCOMC__
  740.  
  741. extern "C" void remap_line_asm(uchar *screen_line,uchar *light_lookup,uchar *remap_line,int count);
  742.  
  743. #else */
  744.  
  745. void remap_line_asm2(uchar *addr,uchar *light_lookup,uchar *remap_line,int count)
  746. //inline void remap_line_asm2(uchar *addr,uchar *light_lookup,uchar *remap_line,int count)
  747. {
  748.   while (count--)
  749.   {
  750.     uchar *off=light_lookup+(((long)*remap_line)<<8); 
  751.     remap_line++;
  752.  
  753.     *addr=off[*addr]; 
  754.     addr[1]=off[addr[1]];
  755.     addr[2]=off[addr[2]];
  756.     addr[3]=off[addr[3]];
  757.     addr[4]=off[addr[4]];
  758.     addr[5]=off[addr[5]];
  759.     addr[6]=off[addr[6]];
  760.     addr[7]=off[addr[7]];
  761.     addr+=8;
  762.  
  763.   }
  764. }
  765.  
  766. //#endif
  767.  
  768.  
  769. inline void put_8line(uchar *in_line, uchar *out_line, uchar *remap, uchar *light_lookup, int count)
  770. {
  771.   uchar v;
  772.   int x;
  773.   for (x=0;x<count;x++)                        
  774.   {                                            
  775.     uchar *off=light_lookup+(((long)*remap)<<8);
  776.  
  777.     v=off[*(in_line++)];
  778.     *(out_line++)=v;
  779.     *(out_line++)=v;
  780.  
  781.     v=off[*(in_line++)];
  782.     *(out_line++)=v;
  783.     *(out_line++)=v;
  784.  
  785.     v=off[*(in_line++)];
  786.     *(out_line++)=v;
  787.     *(out_line++)=v;
  788.  
  789.     v=off[*(in_line++)];
  790.     *(out_line++)=v;
  791.     *(out_line++)=v;
  792.  
  793.     v=off[*(in_line++)];
  794.     *(out_line++)=v;
  795.     *(out_line++)=v;
  796.  
  797.     v=off[*(in_line++)];
  798.     *(out_line++)=v;
  799.     *(out_line++)=v;
  800.  
  801.     v=off[*(in_line++)];
  802.     *(out_line++)=v;
  803.     *(out_line++)=v;
  804.  
  805.     v=off[*(in_line++)];
  806.     *(out_line++)=v;
  807.     *(out_line++)=v;
  808.  
  809.     remap++;
  810.   }
  811. }
  812.  
  813.  
  814. void light_screen(image *sc, long screenx, long screeny, uchar *light_lookup, ushort ambient)
  815. {
  816.   int lx_run,ly_run;                     // light block x & y run size in pixels ==  (1<<lx_run)
  817.  
  818.   if (shutdown_lighting && !disable_autolight)
  819.     ambient=shutdown_lighting_value;
  820.  
  821.   switch (light_detail) 
  822.   {
  823.     case HIGH_DETAIL : 
  824.     { lx_run=2; ly_run=1; } break;       // 4 x 2 patches
  825.     case MEDIUM_DETAIL :
  826.     { lx_run=3; ly_run=2; } break;       // 8 x 4 patches  (default)
  827.     case LOW_DETAIL :
  828.     { lx_run=4; ly_run=3; } break;       // 16 x 8 patches
  829.     case POOR_DETAIL :                   // poor detail is no lighting
  830.     return ;
  831.   }
  832.   if ((int)ambient+ambient_ramp<0)
  833.     min_light_level=0;
  834.   else if ((int)ambient+ambient_ramp>63)
  835.     min_light_level=63;
  836.   else min_light_level=(int)ambient+ambient_ramp;
  837.  
  838.   if (ambient==63) return ;
  839.   short cx1,cy1,cx2,cy2;
  840.   sc->get_clip(cx1,cy1,cx2,cy2);
  841.  
  842.   unsigned char *mint=light_lookup+min_light_level*256;
  843.  
  844.   light_patch *first=make_patch_list(cx2-cx1+1,cy2-cy1+1,screenx,screeny);
  845.  
  846.  
  847.   int ytry=(1<<ly_run),xtry=(1<<lx_run);
  848.   int calcx_mask=(0xefffffff-(xtry-1));
  849.   int calcy_mask=(0xefffffff-(ytry-1));
  850.   int scr_w=screen->width();
  851.  
  852.  
  853.   int prefix_x=(screenx&7);
  854.   int prefix=screenx&7;
  855.   if (prefix)
  856.     prefix=8-prefix;
  857.   int suffix_x=cx2-cx1-(screenx&7);
  858.  
  859.   int inside_xoff=(screenx+7)&(~7);
  860.  
  861.   int suffix=(cx2-cx1-prefix+1)&7;
  862.  
  863.  
  864.   long remap_size=((cx2-cx1+1-prefix-suffix)>>lx_run);
  865.  
  866.   uchar *remap_line=(uchar *)jmalloc(remap_size,"light remap line");
  867.  
  868.   light_patch *f=first;
  869.   uchar *screen_line=screen->scan_line(cy1)+cx1;
  870.  
  871.  
  872.   for (int y=cy1;y<=cy2;)
  873.   {
  874.     int x,count;
  875. //    while (f->next && f->y2<y) 
  876. //      f=f->next;
  877.     uchar *rem=remap_line;
  878.  
  879.     int todoy=4-((screeny+y)&3);
  880.     if (y+todoy>cy2)
  881.       todoy=cy2-y+1;
  882.  
  883.     int calcy=((y+screeny)&(~3))-cy1;
  884.     
  885.  
  886.     if (suffix)
  887.     {
  888.       light_patch *lp=f;
  889.       for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || 
  890.                   lp->x1>suffix_x || lp->x2<suffix_x);lp=lp->next);
  891.       long caddr=(long)screen_line+cx2-cx1+1-suffix;
  892.       uchar *r=light_lookup+(((long)calc_light_value(lp,suffix_x+screenx,calcy)<<8));
  893.       switch (todoy)
  894.       {
  895.     case 4 :
  896.     { 
  897.       MAP_PUT(caddr,(long)r,suffix); caddr+=scr_w;
  898.     }
  899.     case 3 :
  900.     { MAP_PUT(caddr,(long)r,suffix); caddr+=scr_w;}
  901.     case 2 :
  902.     { MAP_PUT(caddr,(long)r,suffix); caddr+=scr_w;}
  903.     case 1 :
  904.     { 
  905.       MAP_PUT(caddr,(long)r,suffix);
  906.     }
  907.       }
  908.     }
  909.  
  910.     if (prefix)
  911.     {
  912.       light_patch *lp=f;
  913.       for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || 
  914.                   lp->x1>prefix_x || lp->x2<prefix_x);lp=lp->next);
  915.  
  916.       uchar *r=light_lookup+(((long)calc_light_value(lp,prefix_x+screenx,calcy)<<8));
  917.       long caddr=(long)screen_line;
  918.       switch (todoy)
  919.       {
  920.     case 4 :
  921.     { 
  922.       MAP_PUT(caddr,(long)r,prefix); 
  923.       caddr+=scr_w; 
  924.     }
  925.     case 3 :
  926.     { MAP_PUT(caddr,(long)r,prefix); caddr+=scr_w; }
  927.     case 2 :
  928.     { MAP_PUT(caddr,(long)r,prefix); caddr+=scr_w; }
  929.     case 1 :
  930.     { MAP_PUT(caddr,(long)r,prefix); }
  931.       }
  932.       screen_line+=prefix;
  933.     }
  934.  
  935.  
  936.  
  937.  
  938.     for (x=prefix,count=0;count<remap_size;count++,x+=8,rem++)    
  939.     {
  940.       light_patch *lp=f;
  941.       for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || lp->x1>x || lp->x2<x);lp=lp->next);
  942.       *rem=calc_light_value(lp,x+screenx,calcy);
  943.     }
  944.     uchar *addr,*oaddr;
  945.  
  946.  
  947.     switch (todoy)
  948.     {
  949.       case 4 :    
  950.       remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
  951.       case 3 :
  952.       remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
  953.       case 2 :
  954.       remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
  955.       case 1 :
  956.       remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
  957.     } 
  958.  
  959.  
  960.     screen_line-=prefix;
  961.  
  962.  
  963.  
  964.   }
  965.  
  966.  
  967.   while (first)
  968.   {
  969.     light_patch *p=first;
  970.     first=first->next;
  971.     delete p;
  972.   }
  973.   jfree(remap_line);
  974. }
  975.  
  976.  
  977. void double_light_screen(image *sc, long screenx, long screeny, uchar *light_lookup, ushort ambient,
  978.              image *out, long out_x, long out_y)
  979. {
  980.   if (sc->width()*2+out_x>out->width() ||
  981.       sc->height()*2+out_y>out->height()) 
  982.     return ;   // screen was resized and small_render has not changed size yet
  983.  
  984.  
  985.   int lx_run,ly_run;                     // light block x & y run size in pixels ==  (1<<lx_run)
  986.   switch (light_detail) 
  987.   {
  988.     case HIGH_DETAIL : 
  989.     { lx_run=2; ly_run=1; } break;       // 4 x 2 patches
  990.     case MEDIUM_DETAIL :
  991.     { lx_run=3; ly_run=2; } break;       // 8 x 4 patches  (default)
  992.     case LOW_DETAIL :
  993.     { lx_run=4; ly_run=3; } break;       // 16 x 8 patches
  994.     case POOR_DETAIL :                   // poor detail is no lighting
  995.     return ;
  996.   }
  997.   if ((int)ambient+ambient_ramp<0)
  998.     min_light_level=0;
  999.   else if ((int)ambient+ambient_ramp>63)
  1000.     min_light_level=63;
  1001.   else min_light_level=(int)ambient+ambient_ramp;
  1002.  
  1003.   short cx1,cy1,cx2,cy2;
  1004.   sc->get_clip(cx1,cy1,cx2,cy2);
  1005.  
  1006.  
  1007.   if (ambient==63)      // lights off, just double the pixels
  1008.   {
  1009.     uchar *src=sc->scan_line(0);
  1010.     uchar *dst=out->scan_line(out_y+cy1*2)+cx1*2+out_x;
  1011.     int d_skip=out->width()-sc->width()*2;
  1012.     int x,y;
  1013.     ushort v;
  1014.     for (y=sc->height();y;y--)
  1015.     {
  1016.       for (x=sc->width();x;x--)
  1017.       {
  1018.     v=*(src++);
  1019.     *(dst++)=v;
  1020.     *(dst++)=v;
  1021.       }
  1022.       dst=dst+d_skip;
  1023.       memcpy(dst,dst-out->width(),sc->width()*2);
  1024.       dst+=out->width();
  1025.     }
  1026.  
  1027.     return ;
  1028.   }
  1029.  
  1030.  
  1031.   unsigned char *mint=light_lookup+min_light_level*256;
  1032.  
  1033.   light_patch *first=make_patch_list(cx2-cx1+1,cy2-cy1+1,screenx,screeny);
  1034.  
  1035.  
  1036.   int ytry=(1<<ly_run),xtry=(1<<lx_run);
  1037.   int calcx_mask=(0xefffffff-(xtry-1));
  1038.   int calcy_mask=(0xefffffff-(ytry-1));
  1039.   int scr_w=sc->width();
  1040.   int dscr_w=out->width();
  1041.  
  1042.   int prefix_x=(screenx&7);
  1043.   int prefix=screenx&7;
  1044.   if (prefix)
  1045.     prefix=8-prefix;
  1046.   int suffix_x=cx2-cx1-(screenx&7);
  1047.  
  1048.   int inside_xoff=(screenx+7)&(~7);
  1049.  
  1050.   int suffix=(cx2-cx1-prefix+1)&7;
  1051.  
  1052.  
  1053.   long remap_size=((cx2-cx1+1-prefix-suffix)>>lx_run);
  1054.  
  1055.   uchar *remap_line=(uchar *)jmalloc(remap_size,"light remap line");
  1056.  
  1057.  
  1058.  
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064.  
  1065.  
  1066.  
  1067.  
  1068.   light_patch *f=first;
  1069.   uchar *in_line=sc->scan_line(cy1)+cx1;
  1070.   uchar *out_line=out->scan_line(cy1*2+out_y)+cx1*2+out_x;
  1071.  
  1072.  
  1073.   for (int y=cy1;y<=cy2;)
  1074.   {
  1075.     int x,count;
  1076. //    while (f->next && f->y2<y) 
  1077. //      f=f->next;
  1078.     uchar *rem=remap_line;
  1079.  
  1080.     int todoy=4-((screeny+y)&3);
  1081.     if (y+todoy>cy2)
  1082.       todoy=cy2-y+1;
  1083.  
  1084.     int calcy=((y+screeny)&(~3))-cy1;
  1085.     
  1086.  
  1087.     if (suffix)
  1088.     {
  1089.       light_patch *lp=f;
  1090.       for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || 
  1091.                   lp->x1>suffix_x || lp->x2<suffix_x);lp=lp->next);
  1092.       long caddr=(long)in_line+cx2-cx1+1-suffix;
  1093.       long daddr=(long)out_line+(cx2-cx1+1-suffix)*2;
  1094.  
  1095.       uchar *r=light_lookup+(((long)calc_light_value(lp,suffix_x+screenx,calcy)<<8));
  1096.       switch (todoy)
  1097.       {
  1098.     case 4 : 
  1099.     { 
  1100.       MAP_2PUT(caddr,daddr,(long)r,suffix); daddr+=dscr_w;
  1101.       MAP_2PUT(caddr,daddr,(long)r,suffix); daddr+=dscr_w; caddr+=scr_w;
  1102.     }
  1103.     case 3 :
  1104.     { 
  1105.       MAP_2PUT(caddr,daddr,(long)r,suffix); daddr+=dscr_w;
  1106.       MAP_2PUT(caddr,daddr,(long)r,suffix); daddr+=dscr_w; caddr+=scr_w;
  1107.     }
  1108.     case 2 :
  1109.     { 
  1110.       MAP_2PUT(caddr,daddr,(long)r,suffix); daddr+=dscr_w;
  1111.       MAP_2PUT(caddr,daddr,(long)r,suffix); daddr+=dscr_w; caddr+=scr_w;
  1112.     }
  1113.     case 1 :
  1114.     { 
  1115.       MAP_2PUT(caddr,daddr,(long)r,suffix); daddr+=dscr_w;
  1116.       MAP_2PUT(caddr,daddr,(long)r,suffix); daddr+=dscr_w; caddr+=scr_w;
  1117.     } break;
  1118.       }
  1119.     }
  1120.  
  1121.     if (prefix)
  1122.     {
  1123.       light_patch *lp=f;
  1124.       for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || 
  1125.                   lp->x1>prefix_x || lp->x2<prefix_x);lp=lp->next);
  1126.  
  1127.       uchar *r=light_lookup+(((long)calc_light_value(lp,prefix_x+screenx,calcy)<<8));
  1128.       long caddr=(long)in_line;
  1129.       long daddr=(long)out_line;
  1130.       switch (todoy)
  1131.       {
  1132.     case 4 :
  1133.     { 
  1134.       MAP_2PUT(caddr,daddr,(long)r,prefix); daddr+=dscr_w;
  1135.       MAP_2PUT(caddr,daddr,(long)r,prefix); daddr+=dscr_w; caddr+=scr_w;
  1136.     }
  1137.     case 3 :
  1138.     { 
  1139.       MAP_2PUT(caddr,daddr,(long)r,prefix); daddr+=dscr_w;
  1140.       MAP_2PUT(caddr,daddr,(long)r,prefix); daddr+=dscr_w; caddr+=scr_w;
  1141.     }
  1142.     case 2 :
  1143.     { 
  1144.       MAP_2PUT(caddr,daddr,(long)r,prefix); daddr+=dscr_w;
  1145.       MAP_2PUT(caddr,daddr,(long)r,prefix); daddr+=dscr_w; caddr+=scr_w;
  1146.     }
  1147.     case 1 :
  1148.     { 
  1149.       MAP_2PUT(caddr,daddr,(long)r,prefix); daddr+=dscr_w;
  1150.       MAP_2PUT(caddr,daddr,(long)r,prefix); daddr+=dscr_w; caddr+=scr_w;
  1151.     } break;
  1152.       }
  1153.       in_line+=prefix;
  1154.       out_line+=prefix*2;
  1155.     }
  1156.  
  1157.  
  1158.  
  1159.  
  1160.     for (x=prefix,count=0;count<remap_size;count++,x+=8,rem++)    
  1161.     {
  1162.       light_patch *lp=f;
  1163.       for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || lp->x1>x || lp->x2<x);lp=lp->next);
  1164.       *rem=calc_light_value(lp,x+screenx,calcy);
  1165.     }
  1166.  
  1167.     rem=remap_line;
  1168.  
  1169.     put_8line(in_line,out_line,rem,light_lookup,count); 
  1170.     memcpy(out_line+dscr_w,out_line,count*16);
  1171.     out_line+=dscr_w;
  1172.     in_line+=scr_w; out_line+=dscr_w; y++; todoy--;
  1173.     if (todoy)
  1174.     {
  1175.       put_8line(in_line,out_line,rem,light_lookup,count); 
  1176.       memcpy(out_line+dscr_w,out_line,count*16);
  1177.       out_line+=dscr_w;
  1178.       in_line+=scr_w; out_line+=dscr_w; y++; todoy--;
  1179.       if (todoy)
  1180.       {
  1181.     put_8line(in_line,out_line,rem,light_lookup,count); 
  1182.     memcpy(out_line+dscr_w,out_line,count*16);
  1183.     out_line+=dscr_w;
  1184.     in_line+=scr_w; out_line+=dscr_w; y++; todoy--;
  1185.     if (todoy)
  1186.     {
  1187.       put_8line(in_line,out_line,rem,light_lookup,count); 
  1188.       memcpy(out_line+dscr_w,out_line,count*16);
  1189.       out_line+=dscr_w;
  1190.       in_line+=scr_w; out_line+=dscr_w; y++;
  1191.     }
  1192.       }
  1193.     }      
  1194.     in_line-=prefix;
  1195.     out_line-=prefix*2;
  1196.   } 
  1197.  
  1198.  
  1199.   while (first)
  1200.   {
  1201.     light_patch *p=first;
  1202.     first=first->next;
  1203.     delete p;
  1204.   }
  1205.   jfree(remap_line);
  1206. }
  1207.  
  1208.  
  1209.  
  1210.  
  1211. void add_light_spec(spec_directory *sd, char *level_name)
  1212. {
  1213.   long size=4+4;  // number of lights and minimum light levels
  1214.   for (light_source *f=first_light_source;f;f=f->next)
  1215.     size+=6*4+1;
  1216.   sd->add_by_hand(new spec_entry(SPEC_LIGHT_LIST,"lights",NULL,size,0));  
  1217. }
  1218.  
  1219. void write_lights(bFILE *fp)
  1220. {
  1221.   int t=0;
  1222.   light_source *f=first_light_source;
  1223.   for (;f;f=f->next) t++;
  1224.   fp->write_long(t);
  1225.   fp->write_long(min_light_level);
  1226.   for (f=first_light_source;f;f=f->next)
  1227.   {
  1228.     fp->write_long(f->x);
  1229.     fp->write_long(f->y);
  1230.     fp->write_long(f->xshift);
  1231.     fp->write_long(f->yshift);
  1232.     fp->write_long(f->inner_radius);
  1233.     fp->write_long(f->outer_radius);
  1234.     fp->write_byte(f->type);
  1235.   }
  1236. }
  1237.  
  1238.  
  1239. void read_lights(spec_directory *sd, bFILE *fp, char *level_name)
  1240. {
  1241.   delete_all_lights();
  1242.   spec_entry *se=sd->find("lights");
  1243.   if (se)
  1244.   {
  1245.     fp->seek(se->offset,SEEK_SET);
  1246.     long t=fp->read_long();
  1247.     min_light_level=fp->read_long();
  1248.     light_source *last;
  1249.     while (t)
  1250.     {
  1251.       t--;
  1252.       long x=fp->read_long();
  1253.       long y=fp->read_long();
  1254.       long xshift=fp->read_long();
  1255.       long yshift=fp->read_long();
  1256.       long ir=fp->read_long();
  1257.       long ora=fp->read_long();
  1258.       long ty=fp->read_byte();
  1259.  
  1260.       light_source *p=new light_source(ty,x,y,ir,ora,xshift,yshift,NULL);
  1261.       
  1262.       if (first_light_source)
  1263.         last->next=p;
  1264.       else first_light_source=p;
  1265.       last=p;
  1266.     }
  1267.   }
  1268. }
  1269.  
  1270.  
  1271.  
  1272.  
  1273.  
  1274.  
  1275.